package cn.blu10ph.trustshare.controller;

import cn.blu10ph.trustshare.bean.node.TrustNode;
import cn.blu10ph.trustshare.bean.notice.GetNoticesMsg;
import cn.blu10ph.trustshare.bean.notice.Notice;
import cn.blu10ph.trustshare.bean.notice.TrustNotice;
import cn.blu10ph.trustshare.config.ServiceConfig;
import cn.blu10ph.trustshare.constant.Constant;
import cn.blu10ph.trustshare.core.PGPManager;
import cn.blu10ph.trustshare.core.ServiceCore;
import cn.blu10ph.trustshare.service.DHTMsgService;
import cn.blu10ph.trustshare.service.NoticeService;
import cn.blu10ph.trustshare.util.HashAndSignUtil;
import cn.blu10ph.trustshare.util.PgpUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.openpgp.PGPException;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * <p> NoticeController </p >
 *
 * @author cxx
 * @date 2024/4/10 23:23
 */
@Slf4j
@RestController
@RequestMapping("/notice")
public class NoticeController {

    @Resource
    ServiceConfig config;

    @Resource
    PGPManager pgpManager;

    @Resource
    ServiceCore serviceCore;

    @Resource
    NoticeService noticeService;

    @GetMapping(value = "/getList")
    public List<TrustNotice> getList(String[] trustLevel, String bashHash, String infoHash, String type, String from) {
        log.info("Rest get notice list:{},{},{},{},{}", trustLevel, bashHash, infoHash, type, from);
        Set<String> trustLevels = new HashSet<>(Arrays.asList(trustLevel));
        Set<String> nodeIds = pgpManager.getNodeIdByTrustLevel(trustLevels);
        log.info("Rest get notice list nodes:{}", nodeIds);
        return noticeService.findMsg(nodeIds, new GetNoticesMsg(bashHash, infoHash, type, from));
    }

    @GetMapping(value = "/get")
    public TrustNotice get(String infoHash) {
        log.info("Rest get notice:{}", infoHash);
        return noticeService.get(infoHash);
    }

    @PostMapping(value = "/add")
    public void add(@RequestBody Notice notice) throws NoSuchAlgorithmException, PGPException, IOException {
        log.info("Rest add notice:{}", notice);
        TrustNode self = serviceCore.getSelfNode();
        notice.setFromNode(self.getNodeId());
        // infoHash
        notice.setTime(System.currentTimeMillis());
        String infoHash = HashAndSignUtil.getNoticeHash(notice);
        notice.setInfoHash(infoHash);

        // sign
        TrustNotice trustNotice = new TrustNotice(notice);
        trustNotice.setTime(System.currentTimeMillis());
        trustNotice.setNonce(HashAndSignUtil.getNonce(trustNotice.getTime()));
        String signHash = HashAndSignUtil.getNoticeSignHash(trustNotice);
        String sign = PgpUtil.createSignature(signHash, PGPManager.getSecretKey(), config.getPassword());
        trustNotice.setSign(sign);

        noticeService.add(trustNotice);
    }

    @GetMapping(value = "/remove")
    public void remove(String infohash) {
        log.info("Rest remove notice:{}", infohash);
        noticeService.remove(infohash);
    }

    @GetMapping(value = "/flushed")
    public void flushed(
            String[] trustLevel, String baseHash, String infoHash, String type, String fromNode
    ) {
        log.info("Rest flushed notice:{},{},{},{},{}", trustLevel, baseHash, infoHash, type, fromNode);
        // get node list by level
        Set<String> trustLevels = new HashSet<>(Arrays.asList(trustLevel));
        Set<String> nodeIds = pgpManager.getNodeIdByTrustLevel(trustLevels);
        log.info("Rest flushed notice nodes:{}", nodeIds);
        DHTMsgService<GetNoticesMsg> msgService = serviceCore.getMsgService(Constant.MSG_TYPE_GET_NOTICES);
        // foreach node list
        nodeIds.forEach(nodeId->{
            TrustNode node = serviceCore.getNode(nodeId);
            // send get_notice
            GetNoticesMsg params = new GetNoticesMsg(baseHash, infoHash, type, fromNode);
            try {
                msgService.sendQuery(node, params);
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        });
    }

}
